home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d8 / pdriver5.arc / 3C503.ASM < prev    next >
Assembly Source File  |  1989-12-17  |  38KB  |  1,084 lines

  1. version    equ    2
  2.  
  3.     include    defs.asm
  4.  
  5. ;/* PC/FTP Packet Driver source, conforming to version 1.05 of the spec,
  6. ;*  for the 3-Com 3C503 interface card.
  7. ;*  Robert C Clements, K1BC, 14 February, 1989
  8. ;*  Portions (C) Copyright 1988, 1989 Robert C Clements
  9. ;*
  10. ;  Copyright, 1988, 1989, Russell Nelson
  11.  
  12. ;   This program is free software; you can redistribute it and/or modify
  13. ;   it under the terms of the GNU General Public License as published by
  14. ;   the Free Software Foundation, version 1.
  15. ;
  16. ;   This program is distributed in the hope that it will be useful,
  17. ;   but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. ;   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19. ;   GNU General Public License for more details.
  20. ;
  21. ;   You should have received a copy of the GNU General Public License
  22. ;   along with this program; if not, write to the Free Software
  23. ;   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  24.  
  25. ;* Change history:
  26. ;*  Updated to driver spec version 1.08 Feb. 17, 1989 by Russell Nelson.
  27. ;*  Changes 27 Jul 89 by Bob Clements (/Rcc)
  28. ;*    Added Thick versus Thin Ethernet switch  27 Jul 89 by Bob Clements (/Rcc)
  29. ;*    Added call to memory_test.
  30. ;*    Added rcv_mode logic.  Started, but didn't finish, multicast logic. 
  31. ;*      Fixed get_address to return current, not PROM, address.
  32. ;*      Minor races fixed.
  33.  
  34. code    segment    byte public
  35.     assume    cs:code, ds:code
  36.  
  37. HT    equ    09h
  38. CR    equ    0dh
  39. LF    equ    0ah
  40.  
  41. ;
  42. ;  Packet Driver Error numbers
  43. BAD_HANDLE    equ    1        ;invalid handle number
  44. NO_CLASS    equ    2        ;no interfaces of specified class found
  45. NO_TYPE        equ    3        ;no interfaces of specified type found
  46. NO_NUMBER    equ    4        ;no interfaces of specified number found
  47. BAD_TYPE    equ    5        ;bad packet type specified
  48. NO_MULTICAST    equ    6        ;this interface does not support
  49. CANT_TERMINATE    equ    7        ;this packet driver cannot terminate
  50. BAD_MODE    equ    8        ;an invalid receiver mode was specified
  51. NO_SPACE    equ    9        ;operation failed because of insufficient
  52. TYPE_INUSE    equ    10        ;the type had previously been accessed,
  53. BAD_COMMAND    equ    11        ;the command was out of range, or not
  54. CANT_SEND    equ    12        ;the packet couldn't be sent (usually
  55.  
  56. ; Stuff specific to the 3-Com 3C503 Ethernet controller board
  57. ; WD version in C by Bob Clements, K1BC, May 1988 for the KA9Q TCP/IP package
  58. ; 3Com version based on WD8003E version in .ASM, also by Bob Clements, dated
  59. ;  19 August 1988.  The WD and 3Com cards both use the National DS8390.
  60.  
  61. ; Symbol prefix "EN" is for Ethernet, National chip
  62. ; Symbol prefix "E33" is for _E_thernet, _3_Com 50_3_
  63. ; Symbol prefix "E33G" is for registers in the Gate array ASIC.
  64.  
  65. ; The E33 registers - For the ASIC on the 3C503 card:
  66. ; Offsets from the board's base address, which can be set by
  67. ; jumpers to be one of the following 8 values (hex):
  68. ;  350, 330, 310, 300, 2E0, 2A0, 280, 250
  69. ; Factory default address is 300H.
  70. ; The card occupies a block of 16 I/O addresses.
  71. ; It also occupies 16 addresses at base+400 through base+40F.
  72. ; These high-addressed registers are in the ASIC.
  73. ; Recall that the normal PC I/O decoding is only 10 bits. The 11'th
  74. ; bit (400H) can be used on the same card for additional registers.
  75. ; This offset requires word, not byte, arithmetic
  76. ; on the DX register for the setport macro. Current SETPORT is OK.
  77.  
  78. ; The card can also be jumpered to have the shared memory disabled
  79. ; or enabled at one of four addresses: C8000, CC000, D8000 or DC000.
  80. ; This version of the driver REQUIRES the shared memory to be 
  81. ; enabled somewhere.
  82. ; The card can be operated using direct I/O instructions or by
  83. ; using the PC's DMA channels instead of the shared memory, but
  84. ; I haven't included the code for those other two methods. 
  85. ; They would be needed in a system where all four possible addresses
  86. ; for the shared memory are in use by other devices.  /Rcc
  87.  
  88. ; Blocks of I/O addresses:
  89.  
  90. E33GA        equ    400h    ; Registers in the gate array.
  91. E33_SAPROM    equ    000h    ; Window on station addr prom (if
  92.                 ; E33G_CNTRL bits 3,2 = 0,1
  93.  
  94. ; The EN registers - the DS8390 chip registers
  95. ; These appear at Base+0 through Base+0F when bits 3,2 of
  96. ; E33G_CNTRL are 0,0.
  97. ; There are two (really 3) pages of registers in the chip. You select
  98. ; which page you want, then address them at offsets 00-0F from base.
  99. ; The chip command register (EN_CCMD) appears in both pages.
  100.  
  101. EN_CCMD        equ    000h    ; Chip's command register
  102.  
  103. ; Page 0
  104.  
  105. EN0_STARTPG    equ    001h    ; Starting page of ring bfr
  106. EN0_STOPPG    equ    002h    ; Ending page +1 of ring bfr
  107. EN0_BOUNDARY    equ    003h    ; Boundary page of ring bfr
  108. EN0_TSR        equ    004h    ; Transmit status reg
  109. EN0_TPSR    equ    004h    ; Transmit starting page
  110. EN0_TCNTLO    equ    005h    ; Low  byte of tx byte count
  111. EN0_TCNTHI    equ    006h    ; High byte of tx byte count
  112. EN0_ISR        equ    007h    ; Interrupt status reg
  113. EN0_RCNTLO    equ    00ah    ; Remote byte count reg
  114. EN0_RCNTHI    equ    00bh    ; Remote byte count reg
  115. EN0_RXCR    equ    00ch    ; RX control reg
  116. EN0_TXCR    equ    00dh    ; TX control reg
  117. EN0_COUNTER0    equ    00dh    ; Rcv alignment error counter
  118. EN0_DCFG    equ    00eh    ; Data configuration reg
  119. EN0_COUNTER1    equ    00eh    ; Rcv CRC error counter
  120. EN0_IMR        equ    00fh    ; Interrupt mask reg
  121. EN0_COUNTER2    equ    00fh    ; Rcv missed frame error counter
  122.  
  123. ; Page 1
  124.  
  125. EN1_PHYS    equ    001h    ; This board's physical enet addr
  126. EN1_CURPAG    equ    007h    ; Current memory page
  127. EN1_MULT    equ    008h    ; Multicast filter mask array (8 bytes)
  128.  
  129.  
  130. ; Chip commands in EN_CCMD
  131. ENC_STOP    equ    001h    ; Stop the chip
  132. ENC_START    equ    002h    ; Start the chip
  133. ENC_TRANS    equ    004h    ; Transmit a frame
  134. ENC_NODMA    equ    020h    ; No remote DMA used on this card
  135. ENC_PAGE0    equ    000h    ; Select page 0 of chip registers
  136. ENC_PAGE1    equ    040h    ; Select page 1 of chip registers
  137.  
  138. ; Commands for RX control reg
  139. ENRXCR_MON    equ    020h    ; Monitor mode (no packets rcvd)
  140. ENRXCR_PROMP    equ    010h    ; Promiscuous physical addresses 
  141. ENRXCR_MULTI    equ    008h    ; Multicast (if pass filter)
  142. ENRXCR_BCST    equ    004h    ; Accept broadcasts
  143. ENRXCR_BAD    equ    003h    ; Accept runts and bad CRC frames
  144.  
  145. ; Commands for TX control reg
  146. ENTXCR_LOOP    equ    002h    ; Set loopback mode
  147.  
  148. ; Bits in EN0_DCFG - Data config register
  149. ENDCFG_BM8    equ    048h    ; Set burst mode, 8 deep FIFO
  150.  
  151. ; Bits in EN0_ISR - Interrupt status register
  152. ENISR_RX    equ    001h    ; Receiver, no error
  153. ENISR_TX    equ    002h    ; Transmitter, no error
  154. ENISR_RX_ERR    equ    004h    ; Receiver, with error
  155. ENISR_TX_ERR    equ    008h    ; Transmitter, with error
  156. ENISR_OVER    equ    010h    ; Receiver overwrote the ring
  157. ENISR_COUNTERS    equ    020h    ; Counters need emptying
  158. ENISR_RESET    equ    080h    ; Reset completed
  159. ENISR_ALL    equ    03fh    ; Interrupts we will enable
  160.  
  161. ; Bits in received packet status byte and EN0_RSR
  162. ENPS_RXOK    equ    001h    ; Received a good packet
  163.  
  164. ; Bits in TX status reg
  165.  
  166. ENTSR_COLL    equ    004h    ; Collided at least once
  167. ENTSR_COLL16    equ    008h    ; Collided 16 times and was dropped
  168. ENTSR_FU    equ    020h    ; TX FIFO Underrun
  169.  
  170. ; Registers in the 3-Com custom Gate Array
  171.  
  172. E33G_STARTPG    equ E33GA+00h    ; Start page, must match EN0_STARTPG
  173. E33G_STOPPG    equ E33GA+01h    ; Stop  page, must match EN0_STOPPG
  174. E33G_NBURST    equ E33GA+02h    ; Size of DMA burst before relinquishing bus
  175. E33G_IOBASE    equ E33GA+03h    ; Bit coded: where I/O regs are jumpered.
  176.                 ; (Which you have to know already to read it)
  177. E33G_ROMBASE    equ E33GA+04h    ; Bit coded: Where/whether EEPROM&DPRAM exist
  178. E33G_GACFR    equ E33GA+05h    ; Config/setup bits for the ASIC GA
  179. E33G_CNTRL    equ E33GA+06h    ; Board's main control register
  180. E33G_STATUS    equ E33GA+07h    ; Status on completions.
  181. E33G_IDCFR    equ E33GA+08h    ; Interrupt/DMA config register
  182.                 ; (Which IRQ to assert, DMA chan to use)
  183. E33G_DMAAH    equ E33GA+09h    ; High byte of DMA address reg
  184. E33G_DMAAL    equ E33GA+0ah    ; Low byte of DMA address reg
  185. E33G_VP2    equ E33GA+0bh    ; Vector pointer - for clearing RAM select
  186. E33G_VP1    equ E33GA+0ch    ;  on a system reset, to re-enable EPROM.
  187. E33G_VP0    equ E33GA+0dh    ;  3Com says set this to Ctrl-Alt-Del handler
  188. E33G_FIFOH    equ E33GA+0eh    ; FIFO for programmed I/O data moves ...
  189. E33G_FIFOL    equ E33GA+0fh    ; .. low byte of above.
  190.  
  191. ; Bits in E33G_CNTRL register:
  192.  
  193. ECNTRL_RESET    equ    001h    ; Software reset of the ASIC and 8390
  194. ECNTRL_THIN    equ    002h    ; Onboard thin-net xcvr enable
  195. ECNTRL_SAPROM    equ    004h    ; Map the station address prom
  196. ECNTRL_DBLBFR    equ    020h    ; FIFO configuration bit
  197. ECNTRL_OUTPUT    equ    040h    ; PC-to-3C501 direction if 1
  198. ECNTRL_START    equ    080h    ; Start the DMA logic
  199.  
  200. ; Bits in E33G_STATUS register:
  201.  
  202. ESTAT_DPRDY    equ    080h    ; Data port (of FIFO) ready
  203. ESTAT_UFLW    equ    040h    ; Tried to read FIFO when it was empty
  204. ESTAT_OFLW    equ    020h    ; Tried to write FIFO when it was full
  205. ESTAT_DTC    equ    010h    ; Terminal Count from PC bus DMA logic
  206. ESTAT_DIP    equ    008h    ; DMA In Progress
  207.  
  208. ; Bits in E33G_GACFR register:
  209.  
  210. EGACFR_NORM    equ    049h    ; Enable 8K shared mem, no DMA TC int
  211. EGACFR_IRQOFF    equ    0c9h    ; Above, and disable 8390 IRQ line
  212.  
  213. ; Shared memory management parameters
  214.  
  215. XMIT_MTU    equ    600h    ; Largest packet we have room for.
  216. SM_TSTART_PG    equ    020h    ; First page of TX buffer
  217. SM_RSTART_PG    equ    026h    ; Starting page of RX ring
  218. SM_RSTOP_PG    equ    040h    ; Last page +1 of RX ring
  219.  
  220. ; Description of header of each packet in receive area of shared memory
  221.  
  222. EN_RBUF_STAT    equ    0    ; Received frame status
  223. EN_RBUF_NXT_PG    equ    1    ; Page after this frame
  224. EN_RBUF_SIZE_LO    equ    2    ; Length of this frame
  225. EN_RBUF_SIZE_HI    equ    3    ; Length of this frame
  226. EN_RBUF_NHDR    equ    4    ; Length of above header area
  227.  
  228. ; End of 3C503 parameter definitions
  229.  
  230. ; The following two values may be overridden from the command line.
  231. ; If they are omitted from the command line, these defaults are used.
  232. ; The shared memory base is set by a jumper.  We read it from the
  233. ; card and set up accordingly.
  234.  
  235.     public    int_no, io_addr, thick_or_thin
  236. int_no        db    2,0,0,0        ; Interrupt level
  237. io_addr        dw    0300h,0        ; I/O address for card (jumpers)
  238. thick_or_thin    dw    1,0        ; Non-zero means thin net
  239.     public    mem_base
  240. mem_base    dw    00000h,0    ; Shared memory addr (jumpers)
  241. ; (Not changeable by software in 3C503)    ; (0 if disabled by jumpers)
  242. thin_bit    db    ECNTRL_THIN    ; Default to thin cable
  243. rxcr_bits       db      ENRXCR_BCST     ; Default to ours plus multicast
  244.  
  245.     public    driver_class, driver_type, driver_name
  246. driver_class    db    1        ;from the packet spec
  247. driver_type    db    12        ;from the packet spec
  248. driver_name    db    '3C503',0    ;name of the driver.
  249.  
  250.     public    card_hw_addr, curr_hw_addr, mcast_list_bits, mcast_all_flag
  251. card_hw_addr    db    0,0,0,0,0,0    ;Physical ethernet address
  252. curr_hw_addr    db    0,0,0,0,0,0    ;Address set into the 8390
  253. mcast_list_bits db      0,0,0,0,0,0,0,0 ;Bit mask from last set_multicast_list
  254. mcast_all_flag  db      0               ;Non-zero if hware should have all
  255.                     ; ones in mask rather than this list.
  256.  
  257.     public    rcv_modes
  258. rcv_modes    dw    7        ;number of receive modes in our table.
  259.         dw    0               ;There is no mode zero
  260.         dw    rcv_mode_1
  261.         dw    rcv_mode_2
  262.         dw    rcv_mode_3
  263.         dw    rcv_mode_4
  264.         dw    rcv_mode_5
  265.         dw    rcv_mode_6
  266.  
  267. ; send_pkt: - The Transmit Frame routine
  268.  
  269.     public    send_pkt
  270. send_pkt:
  271. ;enter with ds:si -> packet, cx = packet length.
  272. ;exit with nc if ok, or else cy if error, dh set to error number.
  273.     assume    ds:nothing
  274.     loadport        ; Point at chip command register
  275.     setport EN_CCMD        ; ..
  276.     mov bx,    8000h        ; Avoid infinite loop
  277. tx_wait:
  278.     in al,    dx        ; Get chip command state
  279.     test al,ENC_TRANS    ; Is transmitter still running?
  280.     jz    tx_idle        ; Go if free
  281.     dec    bx        ; Count the timeout
  282.     jnz    tx_wait        ; Fall thru if TX is stuck
  283.                 ; Should count these error timeouts
  284.                 ; Maybe need to add recovery logic here
  285. tx_idle:
  286.     cmp    cx,XMIT_MTU    ; Is this packet too large?
  287.     ja    send_pkt_toobig
  288.  
  289.     cmp cx,    RUNT        ; Is the frame long enough?
  290.     jnb    tx_oklen    ; Go if OK
  291.     mov cx,    RUNT        ; Stretch frame to minimum allowed
  292. tx_oklen:
  293.     push    cx        ; Hold count for later
  294.     loadport        ; Set up for address of TX buffer in
  295.     setport    E33G_GACFR    ; Make sure gate array is set up and
  296.     mov al,    EGACFR_NORM    ;  the RAM is enabled (not EPROM)
  297.     out dx,    al        ; ..
  298.     mov ax,    cs:mem_base    ; Set up ES at the shared RAM
  299.     mov es,    ax        ; ..
  300.     xor ax,    ax        ; Set up DI at base of tx buffer
  301.     mov ah,    SM_TSTART_PG    ; Where to put tx frame
  302.     mov di,    ax        ; ..
  303.     call    movemem
  304.     pop    cx        ; Get back count to give to board
  305.     setport    EN0_TCNTLO    ; Low byte of TX count
  306.     mov al,    cl        ; Get the count
  307.     out dx,    al        ; Tell card the count
  308.     setport    EN0_TCNTHI    ; High byte of TX count
  309.     mov al,    ch        ; Get the count
  310.     out dx,    al        ; Tell card the count
  311.     setport    EN0_TPSR    ; Transmit Page Start Register
  312.     mov al,    SM_TSTART_PG
  313.     out dx,    al        ; Start the transmitter
  314.     setport    EN_CCMD        ; Chip command reg
  315.     mov al,    ENC_TRANS+ENC_NODMA
  316.     out dx,    al        ; Start the transmitter
  317.     clc            ; Successfully started
  318.     ret            ; End of transmit-start routine
  319. send_pkt_toobig:
  320.     mov    dh,NO_SPACE
  321.     stc
  322.     ret
  323.  
  324.  
  325. movemem:
  326. ;does the same thing as "rep movsb", only 50% faster.
  327. ;moves words instead of bytes, and handles the case of both addresses odd
  328. ;efficiently.  There is no way to handle one address odd efficiently.
  329. ;This routine always aligns the source address in the hopes that the
  330. ;destination address will also get aligned.  This is from Phil Karn's
  331. ;code from ec.c, a part of his NET package.  I bummed a few instructions
  332. ;out.
  333.     jcxz    movemem_cnte        ; If zero, we're done already.
  334.     test    si,1            ; Does source start on odd byte?
  335.     jz    movemem_adre        ; Go if not
  336.     movsb                ; Yes, move the first byte
  337.     dec    cx            ; Count that byte
  338. movemem_adre:
  339.     shr    cx,1            ; convert to word count
  340.     rep    movsw            ; Move the bulk as words
  341.     jnc    movemem_cnte        ; Go if the count was even
  342.     movsb                ; Move leftover last byte
  343. movemem_cnte:
  344.     ret
  345.  
  346.  
  347.     public    get_address
  348. get_address:
  349. ;get the address of the interface.
  350. ;enter with es:di -> place to get the address, cx = size of address buffer.
  351. ;exit with nc, cx = actual size of address, or cy if buffer not big enough.
  352. ; Give caller the one currently in the 8390, not necessarily the one in PROM.
  353.     assume ds:code
  354.     cmp cx,    EADDR_LEN    ; Caller wants a reasonable length?
  355.     jb    get_addr_x    ; No, fail.
  356.     mov cx,    EADDR_LEN    ; Move one ethernet address from our copy
  357.     mov si, offset curr_hw_addr     ; Copy from most recent setting
  358.     rep     movsb
  359.     mov cx,    EADDR_LEN    ; Tell caller how many bytes we fed him
  360.     clc            ; Carry off says success
  361.     ret
  362. get_addr_x:
  363.     stc            ; Tell caller our addr is too big for him
  364.     ret
  365.  
  366.  
  367.     public    set_address
  368. set_address:
  369.     assume    ds:nothing
  370. ;enter with ds:si -> Ethernet address, CX = length of address.
  371. ;exit with nc if okay, or cy, dh=error if any errors.
  372. ;
  373.     cmp    cx,EADDR_LEN        ;ensure that their address is okay.
  374.     je    set_address_4
  375.     mov    dh,BAD_ADDRESS
  376.     stc
  377.     jmp    short set_address_done
  378. set_address_4:
  379.     push    cs              ; Copy from them to our RAM copy
  380.     pop     es              ; Destination of move
  381.     mov di, offset curr_hw_addr
  382.     rep     movsb           ; Move their address
  383.     call    set_8390_eaddr  ; Put that address in the chip
  384. set_address_okay:
  385.     mov    cx,EADDR_LEN        ;return their address length.
  386.     clc
  387. set_address_done:
  388.     push    cs
  389.     pop    ds
  390.     assume    ds:code
  391.     ret
  392.  
  393. ; Copy our Ethernet address from curr_hw_addr into the DS8390
  394. set_8390_eaddr:
  395.     push    cs              ; Get it from our local RAM copy
  396.     pop     ds
  397.     mov si, offset curr_hw_addr
  398.     mov cx,    EADDR_LEN    ; Move one ethernet address from our copy
  399.     loadport
  400.     setport    EN_CCMD        ; Chip command register
  401.     sti            ; Protect from irq changing page bits
  402.     mov al,    ENC_NODMA+ENC_PAGE1
  403.     out dx,    al        ; Switch to page one for writing eaddr
  404.     setport    EN1_PHYS    ; Where it goes in 8390
  405. set_8390_1:
  406.     lodsb
  407.     out    dx,al
  408.     inc    dx
  409.     loop    set_8390_1
  410.     loadport
  411.     setport    EN_CCMD        ; Chip command register
  412.     mov al,    ENC_NODMA+ENC_PAGE0
  413.     out dx,    al        ; Restore to page zero
  414.     cli            ; OK for interrupts now
  415.     ret
  416.  
  417. ; Routines to set address filtering modes in the DS8390
  418. rcv_mode_1:     ; Turn off receiver
  419.     mov al,    ENRXCR_MON      ; Set to monitor for counts but accept none
  420.     jmp short rcv_mode_set
  421. rcv_mode_2:     ; Receive only packets to this interface
  422.     mov al, 0               ; Set for only our packets
  423.     jmp short rcv_mode_set
  424. rcv_mode_3:     ; Mode 2 plus broadcast packets (This is the default)
  425.     mov al,    ENRXCR_BCST     ; Set four ours plus broadcasts
  426.     jmp short rcv_mode_set
  427. rcv_mode_4:     ; Mode 3 plus selected multicast packets
  428.     mov al,    ENRXCR_BCST+ENRXCR_MULTI ; Ours, bcst, and filtered multicasts
  429.     mov     mcast_all_flag,0
  430.     jmp short rcv_mode_set
  431. rcv_mode_5:     ; Mode 3 plus ALL multicast packets
  432.     mov al,    ENRXCR_BCST+ENRXCR_MULTI ; Ours, bcst, and filtered multicasts
  433.     mov     mcast_all_flag,1
  434.     jmp short rcv_mode_set
  435. rcv_mode_6:     ; Receive all packets (Promiscuous physical plus all multi)
  436.     mov al,    ENRXCR_BCST+ENRXCR_MULTI+ENRXCR_PROMP
  437.     mov     mcast_all_flag,1
  438. rcv_mode_set:
  439.     push    ax              ; Hold mode until masks are right
  440.     call    set_8390_multi  ; Set the multicast mask bits in chip
  441.     pop     ax
  442.     loadport
  443.     setport    EN0_RXCR    ; Set receiver to selected mode
  444.     out dx,    al
  445.     mov     rxcr_bits,al    ; Save a copy of what we set it to
  446.     ret
  447.  
  448.  
  449.     public    set_multicast_list
  450. set_multicast_list:
  451. ;enter with es:di ->list of multicast addresses, cx = number of bytes.
  452. ;return nc if we set all of them, or cy,dh=error if we didn't.
  453.     mov    dh,NO_MULTICAST
  454.     stc
  455.     ret
  456.  
  457.  
  458.     public    get_multicast_list
  459. get_multicast_list:
  460. ;return with nc, es:di ->list of multicast addresses, cx = number of bytes.
  461. ;return cy, NO_ERROR if we don't remember all of the addresses ourselves.
  462. ;return cy, NO_MULTICAST if we don't implement multicast.
  463.     mov    dh,NO_MULTICAST
  464.     stc
  465.     ret
  466.  
  467.  
  468. ; Set the multicast filter mask bits in case promiscuous rcv wanted
  469. set_8390_multi:
  470.     loadport
  471.     setport    EN_CCMD        ; Chip command register
  472.     mov cx,    8        ; Eight bytes of multicast filter
  473.     mov si, offset mcast_list_bits  ; Where bits are, if not all ones
  474.     push    cs
  475.     pop     ds
  476.     sti            ; Protect from irq changing page bits
  477.     mov al,    ENC_NODMA+ENC_PAGE1
  478.     out dx,    al        ; Switch to page one for writing eaddr
  479.     setport    EN1_MULT    ; Where it goes in 8390
  480.     mov al, mcast_all_flag  ; Want all ones or just selected bits?
  481.     or al,  al
  482.     je      set_mcast_2     ; Just selected ones
  483.     mov al,    0ffh        ; Ones for filter
  484. set_mcast_all:
  485.     out dx,    al        ; Write a mask byte
  486.     inc    dl        ; Step to next one
  487.     loop    set_mcast_all    ; ..    
  488.     jmp short set_mcast_x
  489.  
  490. set_mcast_2:
  491.     lodsb                   ; Get a byte of mask bits
  492.     out dx,    al        ; Write a mask byte
  493.     inc    dl        ; Step to next I/O register
  494.     loop    set_mcast_2     ; ..    
  495. set_mcast_x:
  496.     loadport
  497.     setport    EN_CCMD        ; Chip command register
  498.     mov al,    ENC_NODMA+ENC_PAGE0
  499.     out dx,    al        ; Restore to page zero
  500.     cli            ; OK for interrupts now
  501.     ret
  502.  
  503.     public    reset_interface
  504. reset_interface:
  505.     assume ds:code
  506.     loadport        ; Base of I/O regs
  507.     setport    EN_CCMD        ; Chip command reg
  508.     mov al,    ENC_STOP+ENC_NODMA
  509.     out dx,    al        ; Stop the DS8390
  510.     setport    EN0_ISR        ; Interrupt status reg
  511.     mov al,    0ffh        ; Clear all pending interrupts
  512.     out dx,    al        ; ..
  513.     setport    EN0_IMR        ; Interrupt mask reg
  514.     xor al,    al        ; Turn off all enables
  515.     out dx,    al        ; ..
  516.     ret
  517.  
  518. ; Linkages to non-device-specific routines
  519. ;called when we want to determine what to do with a received packet.
  520. ;enter with cx = packet length, es:di -> packet type.
  521. ;It returns with es:di = 0 if don't want this type or if no buffer available.
  522.     extrn    recv_find: near
  523.  
  524. ;called after we have copied the packet into the buffer.
  525. ;enter with ds:si ->the packet, cx = length of the packet.
  526.     extrn    recv_copy: near
  527.  
  528.     extrn    count_in_err: near
  529.     extrn    count_out_err: near
  530.  
  531.     public    recv
  532. recv:
  533. ;called from the recv isr.  All registers have been saved, and ds=cs.
  534. ;Actually, not just receive, but all interrupts come here.
  535. ;Upon exit, the interrupt will be acknowledged.
  536.  
  537.     assume    ds:code
  538. check_isr:            ; Was there an interrupt from this card?
  539.     loadport        ; Point at card's I/O port base
  540.     setport    E33G_GACFR    ; Make sure gate array is set up and
  541.     mov al,    EGACFR_NORM    ;  the RAM is enabled (not EPROM)
  542.     out dx,    al        ; ..
  543.     setport    EN0_ISR        ; Point at interrupt status register
  544.     in al,    dx        ; Get pending interrupts
  545.     and al,    ENISR_ALL    ; Any?
  546.     jnz    isr_test_overrun
  547.     jmp    interrupt_done    ; Go if none
  548. ; First, a messy procedure for handling the case where the rcvr
  549. ; over-runs its ring buffer.  This is spec'ed by National for the chip.
  550. ; This is handled differently in sample code from 3Com and from WD.
  551. ; This is close to the WD version.  May need tweaking if it doesn't
  552. ; work for the 3Com card.
  553.  
  554. isr_test_overrun: 
  555.     test al,ENISR_OVER    ; Was there an overrun?
  556.     jnz    recv_overrun    ; Go if so.
  557.     jmp    recv_no_overrun    ; Go if not.
  558. recv_overrun:
  559.     setport    EN_CCMD        ; Stop the chip
  560.     mov al,    ENC_STOP+ENC_NODMA
  561.     out dx,    al        ; Write "stop" to command register
  562.  
  563. ; Remove one frame from the ring
  564.     setport    EN0_BOUNDARY    ; Find end of this frame
  565.     in al,    dx        ; Get memory page number
  566.     inc    al        ; Page plus 1
  567.     cmp al,    SM_RSTOP_PG    ; Wrapped around ring?
  568.     jnz    rcv_ovr_nwrap    ; Go if not
  569.     mov al,    SM_RSTART_PG    ; Yes, wrap the page pointer
  570. rcv_ovr_nwrap:
  571.     xor ah,    ah        ; Convert page to segment
  572.     mov cl,    4
  573.     mov bl,    al        ; Page number as arg to rcv_frm
  574.     shl ax,    cl        ; ..
  575.     add ax,    mem_base    ; Page in this memory
  576.     mov es,    ax        ; Segment pointer to the frame header
  577.     push    es        ; Hold this frame pointer for later
  578.     mov al,    es:[EN_RBUF_STAT]    ; Get the buffer status byte
  579.     test al,ENPS_RXOK    ; Is this frame any good?
  580.     jz    rcv_ovr_ng    ; Skip if not
  581.      call    rcv_frm        ; Yes, go accept it
  582. rcv_ovr_ng:
  583.     pop    es        ; Back to start of this frame
  584.     mov al,    es:[EN_RBUF_NXT_PG]    ; Get pointer to next frame
  585.     dec    al        ; Back up one page
  586.     cmp al,    SM_RSTART_PG    ; Did it wrap?
  587.     jge    rcv_ovr_nwr2
  588.     mov al,    SM_RSTOP_PG-1    ; Yes, back to end of ring
  589. rcv_ovr_nwr2:
  590.     loadport        ; Point at boundary reg
  591.     setport    EN0_BOUNDARY    ; ..
  592.     out dx,    al        ; Set the boundary
  593.     setport    EN0_RCNTLO    ; Point at byte count regs
  594.     xor al,    al        ; Clear them
  595.     out dx,    al        ; ..
  596.     setport    EN0_RCNTHI
  597.     out dx,    al
  598.     setport    EN0_ISR        ; Point at status reg
  599.     mov cx,    8000h        ; Timeout counter
  600. rcv_ovr_rst_loop:
  601.     in al,    dx        ; Is it finished resetting?
  602.     test al,ENISR_RESET    ; ..
  603.     jnz    rcv_ovr_rst    ; Go if so
  604.     dec    cx        ; Loop til reset, or til timeout
  605.     jnz    rcv_ovr_rst_loop
  606. rcv_ovr_rst:
  607.     loadport        ; Point at Transmit control reg
  608.      setport    EN0_TXCR    ; ..
  609.     mov al,    ENTXCR_LOOP    ; Put transmitter in loopback mode
  610.     out dx,    al        ; ..
  611.     setport    EN_CCMD        ; Point at Chip command reg
  612.     mov al,    ENC_START+ENC_NODMA
  613.     out dx,    al        ; Start the chip running again
  614.     setport    EN0_TXCR    ; Back to TX control reg
  615.     xor al,    al        ; Clear the loopback bit
  616.     out dx,    al        ; ..
  617.     setport    EN0_ISR        ; Point at Interrupt status register
  618.     mov al,    ENISR_OVER    ; Clear the overrun interrupt bit
  619.     out dx,    al        ; ..
  620.     call    count_in_err    ; Count the anomaly
  621.      jmp    check_isr    ; Done with the overrun case
  622.  
  623. recv_no_overrun:
  624. ; Handle receive flags, normal and with error (but not overrun).
  625.     test al,ENISR_RX+ENISR_RX_ERR    ; Frame received without overrun?
  626.     jnz    recv_frame    ; Go if so.
  627.     jmp    recv_no_frame    ; Go if not.
  628. recv_frame:
  629.     loadport        ; Point at Chip's Command Reg
  630.      setport    EN_CCMD        ; ..
  631.     mov al,    ENC_NODMA+ENC_PAGE1
  632.     out dx,    al        ; Switch to page 1 registers
  633.     setport    EN1_CURPAG    ;Get current page of rcv ring
  634.     in al,    dx        ; ..
  635.     mov ah,    al        ; Hold current page in AH
  636.      setport    EN_CCMD        ; Back to page zero registers
  637.     mov al,    ENC_NODMA+ENC_PAGE0
  638.     out dx,    al        ; Switch back to page 0 registers
  639.     setport    EN0_BOUNDARY    ;Get boundary page
  640.     in al,    dx        ; ..
  641.     inc    al        ; Step boundary from last used page
  642.     cmp al,    SM_RSTOP_PG    ; Wrap if needed
  643.     jne    rx_nwrap3    ; Go if not
  644.     mov al,    SM_RSTART_PG    ; Wrap to first RX page
  645. rx_nwrap3:
  646.     cmp al,    ah        ; Read all the frames?
  647.     je    recv_frame_break    ; Finished them all
  648.     mov bl,    al        ; Page number as arg to rcv_frm
  649.     xor ah,    ah        ; Make segment pointer to this frame
  650.     mov cl,    4        ; 16 * pages = paragraphs
  651.     shl ax,    cl        ; ..
  652.     add ax,    mem_base    ; That far into shared memory
  653.     mov es,    ax        ; Segment part of pointer
  654.     push    es        ; Hold on to this pointer for later
  655.     mov al,    es:[EN_RBUF_STAT]    ; Get the buffer status byte
  656.     test al,ENPS_RXOK    ; Good frame?
  657.     jz    recv_no_rcv
  658.     call    rcv_frm        ; Yes, go accept it
  659. recv_no_rcv:
  660.     pop    es        ; Back to base of frame
  661.     mov al,    es:[EN_RBUF_NXT_PG]    ; Start of next frame
  662.     dec    al        ; Make previous page for new boundary
  663.     cmp al,    SM_RSTART_PG    ; Wrap around the bottom?
  664.     jge    rcv_nwrap4
  665.     mov al,    SM_RSTOP_PG-1    ; Yes
  666. rcv_nwrap4:
  667.     loadport        ; Point at the Boundary Reg again
  668.      setport    EN0_BOUNDARY    ; ..
  669.     out dx,    al        ; Set new boundary
  670.     jmp    recv_frame    ; See if any more frames
  671.  
  672. recv_frame_break:
  673.     loadport        ; Point at Interrupt Status Reg
  674.      setport    EN0_ISR        ; ..
  675.     mov al,    ENISR_RX+ENISR_RX_ERR+ENISR_OVER
  676.     out dx,    al        ; Clear those requests
  677.     jmp    check_isr    ; See if any other interrupts pending
  678.  
  679. recv_no_frame:                ; Handle transmit flags.
  680.     test al,ENISR_TX+ENISR_TX_ERR    ; Frame transmitted?
  681.     jnz    isr_tx        ; Go if so.
  682.     jmp    isr_no_tx    ; Go if not.
  683. isr_tx:
  684.     mov ah,    al        ; Hold interrupt status bits
  685.     loadport        ; Point at Transmit Status Reg
  686.      setport    EN0_TSR        ; ..
  687.     in al,    dx        ; ..
  688.     test ah,ENISR_TX    ; Non-error TX?
  689.     jz    isr_tx_err    ; No, do TX error completion
  690.     test al,ENTSR_COLL16    ; Jammed for 16 transmit tries?
  691.     jz    isr_tx_njam    ; Go if not
  692.     call    count_out_err    ; Yes, count those
  693. isr_tx_njam:
  694.     setport    EN0_ISR        ; Clear the TX complete flag
  695.     mov al,    ENISR_TX    ; ..
  696.     out dx,    al        ; ..    
  697.     jmp    isr_tx_done
  698. isr_tx_err:
  699.     test al,ENTSR_FU    ; FIFO Underrun?
  700.     jz    isr_txerr_nfu
  701.     call    count_out_err    ; Yes, count those
  702. isr_txerr_nfu:
  703.     loadport        ; Clear the TX error completion flag
  704.     setport    EN0_ISR        ; ..
  705.     mov al,    ENISR_TX_ERR    ; ..
  706.     out dx,    al        ; ..    
  707. isr_tx_done:
  708. ; If TX queue and/or TX shared memory ring buffer were being
  709. ; used, logic to step through them would go here.  However,
  710. ; in this version, we just clear the flags for background to notice.
  711.  
  712.      jmp    check_isr    ; See if any other interrupts on
  713.  
  714. isr_no_tx:
  715. ; Now check to see if any counters are getting full
  716.     test al,ENISR_COUNTERS    ; Interrupt to handle counters?
  717.     jnz    isr_stat    ; Go if so.
  718.     jmp    isr_no_stat    ; Go if not.
  719. isr_stat:
  720. ; We have to read the counters to clear them and to clear the interrupt.
  721. ; Version 1 of the PC/FTP driver spec doesn't give us
  722. ; anything useful to do with the data, though.
  723. ; Fix this up for V2 one of these days.
  724.     loadport        ; Point at first counter
  725.      setport    EN0_COUNTER0    ; ..
  726.     in al,    dx        ; Read the count, ignore it.
  727.     setport    EN0_COUNTER1
  728.     in al,    dx        ; Read the count, ignore it.
  729.     setport    EN0_COUNTER2
  730.     in al,    dx        ; Read the count, ignore it.
  731.     setport    EN0_ISR        ; Clear the statistics completion flag
  732.     mov al,    ENISR_COUNTERS    ; ..
  733.     out dx,    al        ; ..
  734. isr_no_stat:
  735.      jmp    check_isr    ; Anything else to do?
  736.  
  737. interrupt_done:
  738.     ret
  739.  
  740. ; Do the work of copying out a receive frame.
  741. ; Called with bl/ the page number of the frame header in shared memory/
  742. ; Also, es/ the paragraph number of that page.
  743.  
  744. rcv_frm:
  745. ; Old version checked size, memory space, queue length here. Now done
  746. ; in higher level code.
  747. ; Set cx to length of this frame.
  748.     mov ch,    es:[EN_RBUF_SIZE_HI]    ; Extract size of frame
  749.     mov cl,    es:[EN_RBUF_SIZE_LO]    ; Extract size of frame
  750.     sub cx,    EN_RBUF_NHDR        ; Less the header stuff
  751. ; Set es:di to point to Ethernet type field.  es is already at base of
  752. ; page where this frame starts.  Set di after the header and two addresses.
  753.     mov di,    EN_RBUF_NHDR+EADDR_LEN+EADDR_LEN
  754.     push    bx            ; Save page number in bl
  755.     push    cx            ; Save frame size
  756.     push    es
  757.     mov ax,    cs            ; Set ds = code
  758.     mov ds,    ax
  759.     assume    ds:code
  760.     call    recv_find        ; See if type and size are wanted
  761.     pop    ds            ; RX page pointer in ds now
  762.     assume    ds:nothing
  763.     pop    cx
  764.     pop    bx
  765.     cld            ; Copies below are forward, please
  766.     mov ax,    es        ; Did recv_find give us a null pointer?
  767.     or ax,    di        ; ..
  768.     je    rcv_no_copy    ; If null, don't copy the data    
  769.  
  770.     push    cx        ; We will want the count and pointer
  771.     push    es        ;  to hand to client after copying,
  772.     push    di        ;  so save them at this point
  773.  
  774. ;; if ( (((size + 255 + EN_RBUF_NHDR) >> 8) + pg) > SM_RSTOP_PG){
  775.     mov ax,    cx        ; Length of frame
  776.     add ax,    EN_RBUF_NHDR+255 ; Including the overhead bytes, rounded up
  777.     add ah,    bl        ; Compute page with last byte of data in ah
  778.     cmp ah,    SM_RSTOP_PG    ; Over the top of the ring?
  779.     jg    rcopy_wrap    ; Yes, move in two pieces
  780.     mov si,    EN_RBUF_NHDR    ; One piece, starts here in first page (in ds)
  781.     jmp    rcopy_one_piece    ; Go move it
  782.  
  783. rcopy_wrap:
  784. ;; Copy in two pieces due to buffer wraparound. */
  785. ;; n = ((SM_RSTOP_PG - pg) << 8) - EN_RBUF_NHDR;    /* To top of mem */
  786.     mov ah,    SM_RSTOP_PG    ; Compute length of first part
  787.     sub ah,    bl        ;  as all of the pages up to wrap point
  788.     xor al,    al        ; 16-bit count
  789.     sub ax,    EN_RBUF_NHDR    ; Less the four overhead bytes
  790.     sub cx,    ax        ; Move the rest in second part
  791.     push    cx        ; Save count of second part
  792.     mov cx,    ax        ; Count for first move
  793.     mov si,    EN_RBUF_NHDR    ; ds:si points at first byte to move
  794.     shr cx,    1        ; All above are even numbers, do words.
  795.     rep    movsw        ; Move first part of frame
  796.     mov ax,    mem_base    ; Paragraph of base of shared memory
  797.     mov ds,    ax        ; ..
  798.     mov si,    SM_RSTART_PG*256  ; Offset to start of first receive page
  799.     pop    cx        ; Bytes left to move
  800. rcopy_one_piece:
  801.     call    movemem
  802.     pop    si        ; Recover pointer to destination
  803.     pop    ds        ; Tell client it's his source
  804.     pop    cx        ; And it's this long
  805.     assume    ds:nothing
  806.     call    recv_copy    ; Give it to him
  807. rcv_no_copy:
  808.     push    cs        ; Put ds back in code space
  809.     pop    ds        ; ..
  810.     assume    ds:code
  811.     ret            ; That's it for rcv_frm
  812.  
  813.  
  814.     public    recv_exiting
  815. recv_exiting:
  816. ;called from the recv isr after interrupts have been acknowledged.
  817. ;Only ds and ax have been saved.
  818.     assume    ds:nothing
  819.     ret
  820.  
  821.  
  822. ;any code after this will not be kept after initialization.
  823. end_resident    label    byte
  824.  
  825.  
  826.     public    usage_msg
  827. usage_msg    db    "usage: 3C503 <packet_int_no> <int_level(2-5)> <io_addr> <thin_net_flag>",CR,LF,'$'
  828.  
  829.     public    copyright_msg
  830. copyright_msg    db    "Packet driver for 3-Com 3C503, version ",'0'+majver,".",'0'+version,CR,LF
  831.         db    "Portions Copyright 1989, Robert C. Clements, K1BC",CR,LF,'$'
  832.  
  833. cfg_err_msg:
  834.     db    "3C503 Configuration failed. Check parameters.",CR,LF,'$'
  835. no_mem_msg:
  836.     db    "3C503 memory jumper must be set to enable memory.",CR,LF
  837.     db    "Driver cannot run with memory disabled.",'$'
  838. int_no_name:
  839.     db    "Interrupt number ",'$'
  840. io_addr_name:
  841.     db    "I/O port ",'$'
  842. mem_base_name:
  843.     db    "Memory address ",'$'
  844. thick_thin_msg:
  845.     db    "Flag, non-zero if thin Ethernet: ",'$'
  846. mem_busted_msg:
  847.     db    "Shared RAM on 3C503 card is defective or there is an address conflict.",CR,LF,'$'
  848.  
  849.     extrn    set_recv_isr: near
  850.  
  851. ;enter with si -> argument string, di -> word to store.
  852. ;if there is no number, don't change the number.
  853.     extrn    get_number: near
  854.  
  855.     public    parse_args
  856. parse_args:
  857.     mov di,    offset int_no        ; May override interrupt channel
  858.     mov bx,    offset int_no_name    ; Message for it
  859.     call    get_number
  860.     mov di,    offset io_addr        ; May override I/O address
  861.     mov bx,    offset io_addr_name    ; Message for it
  862.     call    get_number
  863.     mov di,    offset thick_or_thin    ; May override thick/thin cable flag
  864.     mov bx,    offset thick_thin_msg    ; Message for it
  865.     call    get_number
  866.     mov ax,    thick_or_thin        ; Now make the right bit
  867.     cmp ax,    0
  868.     je    parse_thin1        ; If zero, leave bit off
  869.     mov al,    ECNTRL_THIN        ; Else the bit for the card
  870. parse_thin1:
  871.     mov    thin_bit,al        ; Save for setting up the card
  872.  
  873. ;    mov di,    offset mem_base        ; Not movable in 3C503
  874. ;    mov bx,    offset mem_base_name    ; Message for it
  875. ;    call    get_number        ; Must get from jumpers.
  876.     ret
  877.  
  878.  
  879. mem_busted:
  880.     mov dx,    offset mem_busted_msg
  881.     jmp    short error
  882. nomem_error:
  883.     mov    dx,offset no_mem_msg
  884.     jmp    short error
  885. cfg_error:
  886.     mov    dx,offset cfg_err_msg
  887. error:
  888.     mov    ah,9        ; Type the msg
  889.     int    21h
  890.     stc            ; Indicate error
  891.     ret            ; Return to common code
  892.  
  893. ; Called once to initialize the 3C503 card
  894.  
  895.     extrn    memory_test: near
  896.     public    etopen
  897. etopen:                ; Initialize interface
  898. ; First, initialize the Gate Array (ASIC) card logic.  Later do the 8390.
  899.     loadport        ; First, pulse the board reset
  900.     setport    E33G_CNTRL
  901.     mov al,    thin_bit    ; Thick or thin cable bit
  902.     or al,    ECNTRL_RESET
  903.     out dx,    al        ; Turn on board reset bit
  904.     and al,    ECNTRL_THIN
  905.     out dx,    al        ; Turn off board reset bit
  906. ; Now get the board's physical address from on-board PROM into card_hw_addr
  907.     sti                     ; Protect the E33G_CNTRL contents
  908.     setport E33G_CNTRL    ; Switch control bits to enable SA PROM
  909.     mov al,    thin_bit
  910.     or al,    ECNTRL_SAPROM
  911.     out dx,    al        ; ..
  912.     setport    E33_SAPROM    ; Where the address prom is
  913.     cld            ; Make sure string mode is right
  914.     push    cs        ; Point es:di at local copy space
  915.     pop    es
  916.     mov di,    offset card_hw_addr
  917.     mov cx,    EADDR_LEN    ; Set count for loop
  918. ini_addr_loop:
  919.     in al,    dx        ; Get a byte of address
  920.     stosb            ; Feed it to caller
  921.     inc    dx        ; Next byte at next I/O port
  922.     loop    ini_addr_loop    ; Loop over six bytes
  923.     loadport        ; Re-establish I/O base after dx mods
  924.     setport E33G_CNTRL    ; Switch control bits to turn off SA PROM
  925.     mov al,    thin_bit
  926.     out dx,    al        ; Turn off SA PROM windowing
  927.     cli                     ; Ok for E33G_CNTRL to change now
  928. ; Point the "Vector Pointer" registers off into the boonies so we
  929. ; don't get the shared RAM disabled on us while we're using it.
  930. ; Ideally a warm boot should reset this too, to get to ROM on this card,
  931. ; but I don't know a guaranteed way to determine that value.
  932.     setport    E33G_VP2
  933.     mov al,    0ffh        ; Point this at the ROM restart location
  934.     out dx,    al        ;  of ffff0h.
  935.     setport E33G_VP1
  936.     out dx,    al
  937.     xor al,    al
  938.     setport E33G_VP0
  939.     out dx,    al
  940. ;Make sure shared memory is jumpered on. Find its address.
  941.     setport E33G_ROMBASE    ; Point at rom/ram cfg reg
  942.     in al,    dx        ; Read it
  943.     test al,0f0h        ; Any bits on?
  944.     jne    memcfg_1    ; Yes
  945.     jmp    nomem_error    ; No, can't run without it
  946. memcfg_1:
  947.     mov bx,    0c600h        ; Build mem segment here
  948.     test al,0c0h        ; DC00 or D800?
  949.     je    memcfg_2    ; No
  950.     add bx,    01000h        ; Yes, make Dx00
  951. memcfg_2:
  952.     test al,0a0h        ; DC00 or CC00?
  953.     je    memcfg_3
  954.     add bx,    00400h        ; Yes, make xC00
  955. memcfg_3:
  956.     mov mem_base,bx        ; Remember segment addr of memory
  957. ; Set up Gate Array's Config Reg to enable and size the RAM.
  958.     setport    E33G_GACFR    ; Make sure gate array is set up and
  959.     mov al,    EGACFR_IRQOFF    ;  the RAM is enabled (not EPROM)
  960.     out dx,    al        ; ..
  961. ; Check the card's memory
  962.     mov ax,    mem_base    ; Set segment of the shared memory
  963.     add ax,    16*SM_TSTART_PG    ;  which starts 2000h up from "base"
  964.     mov cx,    2000h        ; Length of RAM to test
  965.     call    memory_test    ; Check it out
  966.     jz    mem_works    ; Go if it's OK
  967.     jmp    mem_busted    ; Go report failure if it's bad
  968. mem_works:
  969. ; Set up control of shared memory, buffer ring, etc.
  970.     loadport
  971.     setport    E33G_STARTPG    ; Set ASIC copy of rx's first buffer page
  972.     mov al,    SM_RSTART_PG
  973.     out dx,    al
  974.     setport    E33G_STOPPG    ;  and ASIC copy of rx's last buffer page + 1
  975.     mov al,    SM_RSTOP_PG
  976.     out dx,    al
  977. ; Set up interrupt/DMA control register in ASIC.
  978. ; For now, we won't use the DMA, so B0-B3 are zero.
  979.     xor ah,    ah        ; Get the interrupt level from arg line
  980.     mov al,    int_no        ; ..
  981.     cmp al,    9        ; If converted to 9, make back into 2
  982.     jne    get_irq1    ; Not 9
  983.     mov al,    2        ; Card thinks it's IRQ2
  984. get_irq1:            ; Now should have level in range 2-5
  985.     sub ax,    2        ; Make 0-3 for tables
  986.     cmp ax,    5-2        ; In range?
  987.     jna    get_irq2
  988.     jmp    cfg_error    ; If not, can't configure.
  989. get_irq2:
  990.     xor cx,    cx        ; Make the bit for the ASIC
  991.     mov cl,    al        ; Shift count
  992.     mov al,    10h        ; Bit for irq2
  993.     jcxz    get_irq3    ; Go if it's 2
  994.     shl al,    cl        ; Shift over for 3-5
  995. get_irq3:
  996.     setport    E33G_IDCFR    ; Point at ASIC reg for IRQ level
  997.     out dx,    al        ; Set the bit
  998.     setport    E33G_NBURST    ; Set burst size to 8
  999.     mov al,    8
  1000.     out dx,    al        ; ..
  1001.     setport    E33G_DMAAH    ; Set up transmit bfr in DMA addr
  1002.     mov al,    SM_TSTART_PG
  1003.     out dx,    al
  1004.     xor ax,    ax
  1005.     setport E33G_DMAAL
  1006.     out dx,    al
  1007. ; Now, initialize the DS8390 Ethernet Controller chip
  1008. ini_8390:
  1009.     setport    EN_CCMD        ; DS8390 chip's command register
  1010.     mov al,    ENC_NODMA+ENC_PAGE0+ENC_STOP
  1011.     out dx,    al        ; Switch to page zero
  1012.     setport    EN0_ISR        ; Clear all interrupt flags
  1013.     mov al,    0ffh        ; ..
  1014.     out dx,    al        ; ..
  1015.     setport    EN0_DCFG    ; Configure the fifo organization
  1016.     mov al,    ENDCFG_BM8    ; Fifo threshold = 8 bytes
  1017.     out dx,    al
  1018.     setport    EN0_TXCR    ; Set transmitter mode to normal
  1019.     xor al,    al
  1020.     out dx,    al
  1021.     setport    EN0_RXCR    ; Set receiver to monitor mode
  1022.     mov al,    ENRXCR_MON
  1023.     out dx,    al
  1024. ; Set up control of shared memory, buffer ring, etc.
  1025.     setport    EN0_STARTPG    ; Set receiver's first buffer page
  1026.     mov al,    SM_RSTART_PG
  1027.     out dx,    al
  1028.     setport    EN0_STOPPG    ;  and receiver's last buffer page + 1
  1029.     mov al,    SM_RSTOP_PG
  1030.     out dx,    al
  1031.     setport    EN0_BOUNDARY    ; Set initial "last page we have emptied"
  1032.     mov al,    SM_RSTART_PG    ; (WD doc says set to RSTART_PG)
  1033. ;    dec    al        ; (3Com doc says set to RSTOP_PG-1 ?)
  1034. ;                ; (and 3Com handling of BOUNDARY is
  1035. ;                ;  different throughout.)
  1036.     out dx,    al        ; (Check out why WD and 3Com disagree)
  1037.     push    ds              ; Copy from card's address to current address
  1038.     pop     es
  1039.     mov si, offset card_hw_addr
  1040.     mov di, offset curr_hw_addr
  1041.     mov cx, EADDR_LEN       ; Copy one address length
  1042.     rep     movsb           ; ..
  1043.     call    set_8390_eaddr  ; Now set the address in the 8390 chip
  1044.     call    set_8390_multi  ; Put the right stuff into 8390's multicast masks
  1045.     loadport        ; Base of I/O regs
  1046.     setport    EN1_CURPAG    ; Set current shared page for RX to work on
  1047.     mov al,    SM_RSTART_PG+1
  1048.     out dx,    al
  1049.     setport    EN_CCMD        ; Chip command register
  1050.     mov al,    ENC_NODMA+ENC_PAGE0
  1051.     out dx,    al        ; Back to page zero
  1052.     setport    EN0_RCNTLO    ; Clear the byte count registers
  1053.     xor al,    al        ; ..
  1054.     out dx,    al
  1055.     setport    EN0_RCNTHI
  1056.     out dx,    al        ; Clear high byte, too
  1057.     setport    EN0_IMR        ; Clear all interrupt enable flags
  1058.     xor al,    al
  1059.     out dx,    al
  1060.     setport    EN0_ISR        ; Clear all interrupt assertion flags
  1061.     mov al,    0ffh        ; again for safety before making the
  1062.     out dx,    al        ; interrupt be enabled
  1063.     call    set_recv_isr    ; Put ourselves in interrupt chain
  1064.     loadport
  1065.     setport    EN_CCMD        ; Now start the DS8390
  1066.     mov al,    ENC_START+ENC_NODMA
  1067.     out dx,    al        ; interrupt be enabled
  1068.     setport    EN0_RXCR    ; Tell it what frames to accept
  1069.     mov al,    rxcr_bits       ; As most recently set by set_mode
  1070.     out dx,    al
  1071.     setport    E33G_GACFR    ; Now let it interrupt us
  1072.     mov al,    EGACFR_NORM    ;  and leave RAM enabled
  1073.     out dx,    al
  1074.     setport    EN0_IMR        ; Tell card it can cause these interrupts
  1075.     mov al,    ENISR_ALL
  1076.     out dx,    al
  1077.     mov dx,    offset end_resident    ; Report our size
  1078.     clc                ; Say no error
  1079.     ret                ; Back to common code
  1080.  
  1081. code    ends
  1082.  
  1083.     end
  1084.